﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Text;
using ORM.Attribute;

namespace ORM
{
    public class TableObject : ITableObject
    {
        public static int Add<T>(T t, ref string outParas) where T : ITableObject, new()
        {
            string str = "";
            string tableName  = AttributeHelper.GetTableName<T>();
            string dbAlias = AttributeHelper.GetTableFromDbAlias<T>();
            DbHelper helper = new DbHelper(dbAlias);
            return helper.ExecuteNoQuery(String.Format("proc_{0}_add", tableName), GetInsertSqlParameter(t, DbAction.insert), ActionType.StoredProcedure, ref str);
        }
        public static int Remove<T>(string strWhere, ref string outParas) where T : ITableObject, new()
        {
            string tableName  = AttributeHelper.GetTableName<T>();
            string dbAlias = AttributeHelper.GetTableFromDbAlias<T>();
            DbHelper helper = new DbHelper(dbAlias);
            return helper.ExecuteNoQuery("Proc_AllTable_Remove", GetRemoveSqlParameter<T>(tableName, strWhere), ActionType.StoredProcedure, ref outParas);
        }

        /// <summary>
        /// 获取表数据列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="strWhere"></param>
        /// <param name="ds"></param>
        /// <param name="outParas"></param>
        /// <returns></returns>
        public static int GetList<T>(string strWhere, ref DataSet ds, ref string outParas) where T : ITableObject, new()
        {
            return GetList<T>(0, null, strWhere, ref ds, ref outParas);
        }

        /// <summary>
        /// 获取表数据列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="itop"></param>
        /// <param name="strWhere"></param>
        /// <param name="ds"></param>
        /// <param name="outParas"></param>
        /// <returns></returns>
        public static int GetList<T>(int itop, string strWhere, ref DataSet ds, ref string outParas) where T : ITableObject, new()
        {
            return GetList<T>(0, null, strWhere, ref ds, ref outParas);
        }
        /// <summary>
        /// 获取表数据列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fields"></param>
        /// <param name="strWhere"></param>
        /// <param name="ds"></param>
        /// <param name="outParas"></param>
        /// <returns></returns>
        public static int GetList<T>(string fields, string strWhere, ref DataSet ds, ref string outParas) where T : ITableObject, new()
        {
            string tableName = AttributeHelper.GetTableName<T>();
            string dbAlias = AttributeHelper.GetTableFromDbAlias<T>();
            DbHelper helper = new DbHelper(dbAlias);
            return helper.ExecuteQuery(String.Format("Proc_{0}_GetList", tableName),
                                GetListSqlParameter<T>(tableName, 0, fields, strWhere), ActionType.StoredProcedure, ref ds, ref outParas);

        }

        /// <summary>
        /// 获取表数据列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="iTop"></param>
        /// <param name="fields"></param>
        /// <param name="strWhere"></param>
        /// <param name="ds"></param>
        /// <param name="outParas"></param>
        /// <returns></returns>
        public static int GetList<T>(int iTop, string fields, string strWhere, ref DataSet ds, ref string outParas) where T : ITableObject, new()
        {
            string tableName = AttributeHelper.GetTableName<T>();
            string dbAlias = AttributeHelper.GetTableFromDbAlias<T>();
            DbHelper helper = new DbHelper(dbAlias);
            return helper.ExecuteQuery(String.Format("Proc_{0}_GetList", tableName),
                                GetListSqlParameter<T>(tableName, iTop, fields, strWhere), ActionType.StoredProcedure, ref ds, ref outParas);

        }



        public static int GetCustomProc(string dbAlias, string procname, Hashtable keys, ref DataSet ds, ref string outParas)
        {
            int iResult = 0;
            if (String.IsNullOrEmpty(procname)) return iResult;
            
            List<SqlParameter> list = new List<SqlParameter>(keys.Count);
            SqlParameter para = null;
            foreach (DictionaryEntry entry in keys)
            {
                para = new SqlParameter(String.Format("@{0}", entry.Key.ToString()), TypeParseHelper.ParseType(entry.Value.GetType()));
                para.Direction = ParameterDirection.Input;
                para.Value = entry.Value;
                list.Add(para);
            }
            if(para!= null)
            {
                DbHelper helper = new DbHelper(dbAlias);
                iResult = helper.ExecuteQuery(procname, list.ToArray(), ActionType.StoredProcedure, ref ds, ref outParas);
            }
            return iResult;
        }
        public static int GetCustomProc(string procname, Hashtable keys, ref DataSet ds, ref string outParas)
        {
            int iResult = 0;
            if (String.IsNullOrEmpty(procname)) return iResult;

            List<SqlParameter> list = new List<SqlParameter>(keys.Count);
            SqlParameter para = null;
            foreach (DictionaryEntry entry in keys)
            {
                para = new SqlParameter(String.Format("@{0}", entry.Key.ToString()), TypeParseHelper.ParseType(entry.Value.GetType()));
                para.Direction = ParameterDirection.Input;
                para.Value = entry.Value;
                list.Add(para);
            }
            if (para != null)
            {
                DbHelper helper = new DbHelper("");
                iResult = helper.ExecuteQuery(procname, list.ToArray(), ActionType.StoredProcedure, ref ds, ref outParas);
            }
            return iResult;
        }
        public static int GetCustomProc(string procname, Hashtable keys, ref DataTable dt, ref string outParas)
        {
            int iResult = 0;
            if (String.IsNullOrEmpty(procname)) return iResult;

            List<SqlParameter> list = new List<SqlParameter>(keys.Count);
            SqlParameter para = null;
            foreach (DictionaryEntry entry in keys)
            {
                para = new SqlParameter(String.Format("@{0}", entry.Key.ToString()), TypeParseHelper.ParseType(entry.Value.GetType()));
                para.Direction = ParameterDirection.Input;
                para.Value = entry.Value;
                list.Add(para);
            }
            if (para != null)
            {
                DbHelper helper = new DbHelper("");
                iResult = helper.ExecuteQuery(procname, list.ToArray(), ref dt, ref outParas);
            }
            return iResult;
        }
        public static int GetCustomProc(string dbAlias, string procname, Hashtable keys, ref DataTable dt, ref string outParas)
        {
            int iResult = 0;
            if (String.IsNullOrEmpty(procname)) return iResult;

            List<SqlParameter> list = new List<SqlParameter>(keys.Count);
            SqlParameter para = null;
            foreach (DictionaryEntry entry in keys)
            {
                para = new SqlParameter(String.Format("@{0}", entry.Key.ToString()), TypeParseHelper.ParseType(entry.Value.GetType()));
                para.Direction = ParameterDirection.Input;
                para.Value = entry.Value;
                list.Add(para);
            }
            if (para != null)
            {
                DbHelper helper = new DbHelper(dbAlias);
                iResult = helper.ExecuteQuery(procname, list.ToArray(), ref dt, ref outParas);
            }
            return iResult;
        }
        private static SqlParameter[] GetListSqlParameter<T>(string table, int iTop, string cols, string where) where T : ITableObject
        {
            string[] fields;
            if (String.IsNullOrEmpty(cols))
                fields = AttributeHelper.GetFields<T>();
            else
                fields = cols.Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries);

            SqlParameter para = null;
            List<SqlParameter> list = new List<SqlParameter>();

            para = new SqlParameter("@table", SqlDbType.NVarChar, 50);
            para.Direction = ParameterDirection.Input;
            para.Value = table;
            list.Add(para);
            if(iTop < 0)
            {
                para = new SqlParameter("@iTop", SqlDbType.Int, 4);
                para.Direction = ParameterDirection.Input;
                para.Value = iTop;
                list.Add(para);
            }

            para = new SqlParameter("@fields", SqlDbType.NVarChar, 2000);
            para.Direction = ParameterDirection.Input;
            para.Value = String.Join(",", fields).Trim(','); 
            list.Add(para);

            para = new SqlParameter("@where", SqlDbType.NVarChar, 2000);
            para.Direction = ParameterDirection.Input;
            para.Value = where;
            list.Add(para);
            return list.ToArray();
        }

        private static SqlParameter[] GetRemoveSqlParameter<T>(string tablename, string where) where T : ITableObject
        {
            List<SqlParameter> list = new List<SqlParameter>(2);
            SqlParameter para = new SqlParameter("@tablename", SqlDbType.VarChar, 50);
            para.Direction = ParameterDirection.Input;
            para.Value = tablename;
            list.Add(para);

            SqlParameter paras2 = new SqlParameter("@where", SqlDbType.NVarChar, 2000);
            paras2.Direction = ParameterDirection.Input;
            paras2.Value = where;
            list.Add(paras2);
            return list.ToArray();
        }
        /// <summary>
        /// 获取指定对象，指定操作下的SqlParameter数组
        /// </summary>
        /// <typeparam name="T">T类型</typeparam>
        /// <param name="t">T对象实例</param>
        /// <param name="action">操作类型(insert, delete, update, select)</param>
        /// <returns>SqlParameter数组</returns>
        private static SqlParameter[] GetInsertSqlParameter<T>(T t, DbAction action) where T : ITableObject, new()
        {
            PropertyInfo[] infos = typeof(T).GetProperties();
            if (infos.Length == 0) return null;
            List<SqlParameter> list = new List<SqlParameter>();
            string[] keys = null;
            string primarykey = AttributeHelper.GetTablePrimaryKey<T>();
            if(primarykey.Length > 0)
            {
                keys = primarykey.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
            }

            FieldAttribute fieldAttr;
            object objValue = null;

            foreach (PropertyInfo info in infos)
            {
                objValue = AttributeHelper.GetPropertyValue<T>(t, info.Name);
                fieldAttr = AttributeHelper.GetPropertyAttribute(info);
                if (null == fieldAttr) continue;
                if (String.IsNullOrEmpty(fieldAttr.FieldName)) continue;
                if (action == DbAction.insert && !fieldAttr.IsInsert) continue;
                if (action == DbAction.update && !fieldAttr.IsUpdate) continue;

                if(keys != null && Array.Exists(keys, delegate (string s){return 0 == String.Compare(s, fieldAttr.FieldName);}))
                {
                    if(String.IsNullOrEmpty(objValue.ToString()) || "0" == objValue.ToString())
                    {
                        return null;
                        //throw new Exception("主键值不能为空");
                    }
                }
                SqlParameter para = new SqlParameter(String.Format("@{0}", fieldAttr.FieldName),
                                                     TypeParseHelper.ParseType(fieldAttr.FieldType));
                para.Direction = ParameterDirection.Input;
                para.Value = objValue ?? "";
                list.Add(para);
            }

            return list.ToArray();
        }
        /// <summary>
        /// 生成SQL语句
        /// </summary>
        /// <param name="procname"></param>
        /// <param name="tableName"></param>
        /// <param name="parasname"></param>
        /// <param name="fieldType"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        private static string GenProc(string procname, string tableName, string[] parasname, string[] fieldType, DbAction action)
        {
            StringBuilder sql = new StringBuilder("");
            sql.AppendFormat("if not exists(select name from sysobjects(nolock) where name='{0}' and type='P')", procname);
            sql.Append("begin");
            sql.AppendFormat("CREATE PROCEDURE [{0}] ", procname);
            sql.Append("(");
            for (int i = 0; i < parasname.Length; i++)
            {
                sql.AppendFormat("@{0} {1},", parasname[i],fieldType[i]);
            }
            sql = sql.Remove(sql.Length - 1, 1);
            sql.Append(")");
            sql.Append("begin");
            sql.AppendFormat("insert into {0}({1}) VALUES{2};", tableName, String.Join(",", parasname), String.Join(",@", parasname));
            sql.Append("end");
            sql.Append("end");
            return sql.ToString();
        }

        /// <summary>
        /// 过滤字段属性
        /// </summary>
        /// <param name="fieldAttribute"></param>
        /// <param name="objValue"></param>
        /// <returns></returns>
        private static bool FieldFilter(FieldAttribute fieldAttribute, object objValue)
        {
            string strValue = (objValue ?? "").ToString();
            return false;
        }


        private static string GenParasValue(string values, DbFieldType type)
        {
            string pValue = "";
            switch (type)
            {
                case DbFieldType.TINYINT:
                case DbFieldType.INT:
                    pValue = values;
                    break;
                case DbFieldType.VARCHAR:
                case DbFieldType.NVARCHAR:
                case DbFieldType.DATETIME:
                case DbFieldType.TEXT:
                case DbFieldType.NTEXT:
                case DbFieldType.XML:
                    pValue = String.Format("'{0}'", values);
                    break;
                default:
                    break;
            }
            return pValue;
        }
    }
}
